package com.zwg.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.zwg.tingshu.album.config.VodConstantProperties;
import com.zwg.tingshu.album.mapper.AlbumInfoMapper;
import com.zwg.tingshu.album.mapper.TrackInfoMapper;
import com.zwg.tingshu.album.mapper.TrackStatMapper;
import com.zwg.tingshu.album.service.TrackInfoService;
import com.zwg.tingshu.album.service.VodService;
import com.zwg.tingshu.common.constant.SystemConstant;
import com.zwg.tingshu.common.execption.GuiguException;
import com.zwg.tingshu.model.album.AlbumInfo;
import com.zwg.tingshu.model.album.TrackInfo;
import com.zwg.tingshu.model.album.TrackStat;
import com.zwg.tingshu.query.album.TrackInfoQuery;
import com.zwg.tingshu.user.client.UserFeignClient;
import com.zwg.tingshu.vo.album.*;
import com.zwg.tingshu.vo.album.*;
import com.zwg.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;
	@Autowired
	private VodConstantProperties props;
	@Autowired
	private AlbumInfoMapper albumInfoMapper;
	@Autowired
	private VodService vodService;
	@Autowired
	private TrackStatMapper trackStatMapper;
	@Autowired
	private UserFeignClient userFeignClient;

	/**
	 * 查询当前用户待购买声音列表（加用户已购买声音排除掉）
	 *
	 * @param userId 用户ID
	 * @param trackId 声音ID
	 * @param trackCount 数量
	 * @return
	 */
	@Override
	public List<TrackInfo> getWaitBuyTrackInfoList(Long userId, Long trackId, int trackCount) {
		//1.根据声音ID查询声音对象-得到专辑ID跟声音序号
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		//2.远程调用"用户服务"获取用户已购买声音ID集合
		List<Long> userPaidTrackIdList = userFeignClient.getUserPaidTrackIdList(trackInfo.getAlbumId()).getData();
		//3.根据专辑ID+当前声音序号查询大于当前声音待购买声音列表
		LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
		queryWrapper.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum());
		//3.1 去掉已购买过声音
		if(CollectionUtil.isNotEmpty(userPaidTrackIdList)){
			queryWrapper.notIn(TrackInfo::getId, userPaidTrackIdList);
		}
		//3.2 限制购买数量(用户选择购买数量)
		queryWrapper.last("limit "+trackCount);
		//3.3 只查询指定列：封面图片、声音名称、声音ID、所属专辑ID
		queryWrapper.select(TrackInfo::getId, TrackInfo::getTrackTitle, TrackInfo::getCoverUrl, TrackInfo::getAlbumId);
		//3.4 对声音进行排序：按照序号升序
		queryWrapper.orderByAsc(TrackInfo::getOrderNum);
		List<TrackInfo> waitBuyTrackList = trackInfoMapper.selectList(queryWrapper);
		if (CollectionUtil.isEmpty(waitBuyTrackList)) {
			throw new GuiguException(400, "该专辑下没有符合购买要求声音");
		}
		return waitBuyTrackList;
	}

	/**
	 * 获取当前用户分集购买声音列表
	 *
	 * @param trackId 声音ID
	 * @return [{name:"本集", price:0.2, trackCount:1},{name:"后10集", price:2, trackCount:10},...,{name:"全集", price:*, trackCount:*}]
	 */
	@Override
	public List<Map<String, Object>> getUserWaitBuyTrackPayList(Long trackId) {
		//1.根据声音ID查询声音对象-得到专辑ID跟声音序号
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		//2.根据专辑ID+当前声音序号查询大于当前声音待购买声音列表
		LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
		queryWrapper.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum());
		List<TrackInfo> waitBuyTrackList = trackInfoMapper.selectList(queryWrapper);
		if (CollectionUtil.isEmpty(waitBuyTrackList)) {
			throw new GuiguException(400, "该专辑下没有符合购买要求声音");
		}
		//3.远程调用"用户服务"获取用户已购买声音ID集合
		List<Long> userPaidTrackIdList = userFeignClient.getUserPaidTrackIdList(trackInfo.getAlbumId()).getData();
		//4.将待购买声音列表中用户已购买声音排除掉-得到实际代购买声音列表
		if (CollectionUtil.isNotEmpty(userPaidTrackIdList)) {
			waitBuyTrackList = waitBuyTrackList.stream()
					.filter(waitTrackInfo -> !userPaidTrackIdList.contains(waitTrackInfo.getId())) //排除掉已购声音ID
					.collect(Collectors.toList());
		}
		//5.基于实际购买声音列表长度，动态构建分集购买对象
		List<Map<String, Object>> mapList = new ArrayList<>();
		if (CollectionUtil.isNotEmpty(waitBuyTrackList)) {
			//5.1 根据专辑ID查询专辑得到单集价格
			AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
			BigDecimal price = albumInfo.getPrice();
			//5.1 构建本集购买对象
			Map<String, Object> currMap = new HashMap<>();
			currMap.put("name", "本集");
			currMap.put("price", price);
			currMap.put("trackCount", 1);
			mapList.add(currMap);
			//5.2 判断待购买声音数量 数量<10 动态展示后count集合 价格=count*price 数量=count
			int count = waitBuyTrackList.size();
			//5.3 数量>=10 固定显示后10集 价格=10*price 数量=10
			//if (count >= 10) {
			// Map<String, Object> map = new HashMap<>();
			// map.put("name", "后10集");
			// map.put("price", price.multiply(new BigDecimal("10")));
			// map.put("trackCount", 10);
			// mapList.add(map);
			//}
			////5.3 数量>10 and 数量<20 动态展示：后count集合（全集） 价格=count*price 数量=count 相当于全集
			//if (count > 10 && count < 20) {
			// Map<String, Object> map = new HashMap<>();
			// map.put("name", "后"+count+"集(全集)");
			// map.put("price", price.multiply(new BigDecimal(count)));
			// map.put("trackCount", count);
			// mapList.add(map);
			//}
			//if (count >= 20) {
			//
			////5.4 数量>=20 固定显示后20集 价格=20*price 数量=20
			// Map<String, Object> map = new HashMap<>();
			// map.put("name", "后20集");
			// map.put("price", price.multiply(new BigDecimal("20")));
			// map.put("trackCount", 20);
			// mapList.add(map);
			//}
			////5.4 数量>20 and 数量<30 动态展示：后count集合（全集） 价格=count*price 数量=count 相当于全集
			//if (count > 20 && count < 30) {
			// Map<String, Object> map = new HashMap<>();
			// map.put("name", "后"+count+"集(全集)");
			// map.put("price", price.multiply(new BigDecimal(count)));
			// map.put("trackCount", count);
			// mapList.add(map);
			//}
			////5.5 数量>=30 固定显示后30集 价格=30*price 数量=30
			//if (count >= 30) {
			// Map<String, Object> map = new HashMap<>();
			// map.put("name", "后30集");
			// map.put("price", price.multiply(new BigDecimal("30")));
			// map.put("trackCount", 30);
			// mapList.add(map);
			//}
			////5.5 数量>30 and 数量<40 动态展示：后count集合（全集） 价格=count*price 数量=count 相当于全集
			//if (count > 30 && count < 40) {
			// Map<String, Object> map = new HashMap<>();
			// map.put("name", "后"+count+"集(全集)");
			// map.put("price", price.multiply(new BigDecimal(count)));
			// map.put("trackCount", count);
			// mapList.add(map);
			//}
			//
			////5.5 数量>=40 固定显示后40集 价格=40*price 数量=40
			//if (count >= 40) {
			// Map<String, Object> map = new HashMap<>();
			// map.put("name", "后40集");
			// map.put("price", price.multiply(new BigDecimal("40")));
			// map.put("trackCount", 40);
			// mapList.add(map);
			//}
			////5.5 数量>40 and 数量<50 动态展示：后count集合（全集） 价格=count*price 数量=count 相当于全集
			//if (count > 40 && count < 50) {
			// Map<String, Object> map = new HashMap<>();
			// map.put("name", "后"+count+"集(全集)");
			// map.put("price", price.multiply(new BigDecimal(count)));
			// map.put("trackCount", count);
			// mapList.add(map);
			//}
			// 18
			for (int i = 10; i <= 50; i += 10) {
				//判断数量>i 固定显示后i集
				if (count > i) {
					Map<String, Object> map = new HashMap<>();
					map.put("name", "后" + i + "集");
					map.put("price", price.multiply(new BigDecimal(i)));
					map.put("trackCount", i);
					mapList.add(map);
				} else {
					//反之全集（动态构建后count集合）
					Map<String, Object> map = new HashMap<>();
					map.put("name", "后" + count + "集");
					map.put("price", price.multiply(new BigDecimal(count)));
					map.put("trackCount", count);
					mapList.add(map);
					break;
				}
			}
		}
		return mapList;
	}

	/**
	 * 根据声音ID，查询声音统计信息
	 * @param trackId
	 * @return
	 */
	@Override
	public TrackStatVo getTrackStatVo(Long trackId) {
		return trackInfoMapper.getTrackStatVo(trackId);
	}


	/**
	 * 分页获取专辑下声音列表，动态根据用户情况展示声音付费标识
	 *
	 * @param userId 用户ID
	 * @param albumId 专辑ID
	 * @param pageInfo 分页对象
	 * @return
	 */
	@Override
	public Page<AlbumTrackListVo> getAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long albumId, Long userId) {
		//1.根据专辑ID分页获取该专辑下包含声音列表（包含声音统计信息）-默认声音付费标识为false
		pageInfo = albumInfoMapper.getAlbumTrackPage(pageInfo, albumId);
		//2.TODO 动态判断当前页中每个声音付费标识 关键点：找出付费情况
		//2.根据专辑ID查询专辑信息
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		Assert.notNull(albumInfo, "专辑：{}不存在", albumId);
		String payType = albumInfo.getPayType();
		//3.处理用户未登录情况
		if (userId == null) {
			//3.1 判断专辑付费类型：VIP免费（0102）或 付费（0103） 除了免费试听外声音都应该设置付费标识
			if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType) || SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
				//3.2 获取本页中声音列表，过滤将声音序号大于免费试听集数声音付费标识设置为true
				pageInfo.getRecords()
						.stream()
						.filter(albumTrackVo -> albumTrackVo.getOrderNum() > albumInfo.getTracksForFree()) //过滤获取除免费试听以外声音
						.collect(Collectors.toList())
						.stream().forEach(albumTrackListVo -> {
							albumTrackListVo.setIsShowPaidMark(true);
						});
			}
		} else {
			//4.处理用户已登录情况
			//4.1 远程调用用户服务获取用户信息得到用户身份
			UserInfoVo userInfoVo = userFeignClient.getUserInfoVoByUserId(userId).getData();
			Assert.notNull(userInfoVo, "用户{}不存在", userId);
			Integer isVip = userInfoVo.getIsVip();
			//4.2 默认设置需要进一步确定购买情况标识：默认false
			Boolean isNeedCheckPayStatus = false;
			//4.2.1 如果专辑付费类型 VIP免费
			if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {
				//当前用户为普通用户或VIP会员过期
				if (isVip.intValue() == 0) {
					isNeedCheckPayStatus = true;
				}
				if (isVip.intValue() == 1 && new Date().after(userInfoVo.getVipExpireTime())) {
					isNeedCheckPayStatus = true;
				}
			}
			//4.2.2 如果专辑付费类型 付费
			if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
				//当前用户为普通用户或VIP会员过期
				isNeedCheckPayStatus = true;
			}
			if (isNeedCheckPayStatus) {
				//4.3 进一步确定用户是否购买专辑或声音-远程调用用户服务获取本页中专辑或者声音购买情况
				//本页中需要检查购买情况声音列表，过滤掉当前页免费试听声音
				List<AlbumTrackListVo> needCheckTrackList = pageInfo.getRecords().stream()
						.filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree())
						.collect(Collectors.toList());
				//本页中需要检查购买情况声音ID列表，过滤掉当前页免费试听声音
				List<Long> needCheckTrackIdList = needCheckTrackList.stream()
						.map(albumTrackListVo -> albumTrackListVo.getTrackId())
						.collect(Collectors.toList());
				Map<Long, Integer> userPayStatusTrackMap = userFeignClient.userIsPaidTrack(userId, albumId, needCheckTrackIdList).getData();
				//4.4 循环当前页中声音列表-跟返回用户购买情况声音集合逐一判断
				needCheckTrackList.stream().forEach(needCheckTrack -> {
					Integer payStatus = userPayStatusTrackMap.get(needCheckTrack.getTrackId());
					if (payStatus.intValue() == 0) {
						//4.5 某个声音用户未购买，将设置付费标识 isShowPaidMark:true
						needCheckTrack.setIsShowPaidMark(true);
					}
				});
			}
		}
		return pageInfo;
	}


	/**
	 * 保存专辑下声音
	 *
	 * @param userId 用户ID
	 * @param trackInfoVo 声音信息VO对象
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveTrackInfo(Long userId, TrackInfoVo trackInfoVo) {
		//1.保存声音
		//1.1 将前端提交声音VO对象转为声音PO对象
		TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
		//1.2 为声音对象中基本属性赋值：用户ID、声音来源、声音审核状态（审核通过）
		trackInfo.setUserId(userId);
		trackInfo.setSource("1");
		trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
		//1.3 根据专辑ID查询专辑信息得到专辑已有声音数量，计算出新增声音序号
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
		trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
		//1.4 根据文件唯一标识远程调用腾讯点播平台接口获取音频文件信息（音频时长、大小、音频类型）
		TrackMediaInfoVo trackMediaInfoVo = vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());
		if (trackMediaInfoVo != null) {
			trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
			trackInfo.setMediaSize(trackMediaInfoVo.getSize());
			trackInfo.setMediaType(trackMediaInfoVo.getType());
		}
		//1.5 保存声音得到声音ID
		trackInfoMapper.insert(trackInfo);
		Long trackId = trackInfo.getId();
		//2.新增声音统计信息
		this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PLAY, 0);
		this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COLLECT, 0);
		this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PRAISE, 0);
		this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COMMENT, 0);
		//3.更新专辑包含声音数量
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()+1);
		albumInfoMapper.updateById(albumInfo);
	}

	/**
	 * 新增专辑统计信息
	 * @param trackId 声音ID
	 * @param statType 统计类型
	 * @param statNum 统计数值
	 */
	@Override
	public void saveTrackStat(Long trackId, String statType, int statNum) {
		TrackStat trackStat = new TrackStat();
		trackStat.setTrackId(trackId);
		trackStat.setStatType(statType);
		trackStat.setStatNum(statNum);
		trackStatMapper.insert(trackStat);
	}

	/**
	 * 获取当前登录声音分页列表
	 * @param pageInfo MP分页对象
	 * @param trackInfoQuery 查询声音条件对象
	 * @return
	 */
	@Override
	public Page<TrackListVo> getUserTrackByPage(Page<TrackListVo> pageInfo, TrackInfoQuery trackInfoQuery) {
		return trackInfoMapper.getUserTrackByPage(pageInfo, trackInfoQuery);
	}

	/**
	 * 修改声音
	 *
	 * @param id 声音ID
	 * @param trackInfoVo 声音VO对象
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {
		//1.根据声音ID查询声音对象-判断声音是否变更
		TrackInfo trackInfo = trackInfoMapper.selectById(id);
		//1.2 变更前音频文件唯一标识
		String mediaFileIdBefore = trackInfo.getMediaFileId();
		//1.1 最新提交音频文件唯一标识
		String mediaFileIdAfter = trackInfoVo.getMediaFileId();
		//1.2 拷贝属性
		BeanUtil.copyProperties(trackInfoVo, trackInfo);
		//2.如果声音变更，获取最新声音相关音频信息（时长、大小、类型）为PO对象赋值
		if (!mediaFileIdBefore.equals(mediaFileIdAfter)) {
			TrackMediaInfoVo trackMediaInfo = vodService.getTrackMediaInfo(mediaFileIdAfter);
			if(trackMediaInfo!=null){
				trackInfo.setMediaType(trackMediaInfo.getType());
				trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfo.getDuration()));
				trackInfo.setMediaSize(trackMediaInfo.getSize());
				//4.将变更前声音文件从云点播平台删除
				vodService.deleteTrackMedia(mediaFileIdBefore);
			}
		}
		//3.更新声音
		trackInfoMapper.updateById(trackInfo);
	}

	/**
	 * 根据ID删除声音
	 * @param id 声音ID
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void removeTrackInfo(Long id) {
		//1.根据要删除声音ID查询声音对象-获取当前声音序号用于更新其他声音序号
		TrackInfo trackInfo = trackInfoMapper.selectById(id);
		Integer orderNum = trackInfo.getOrderNum();
		//2.删除声音-逻辑删除
		trackInfoMapper.deleteById(id);
		//3.将比删除声音序号大的声音序号进行递减
		trackInfoMapper.updateTrackNum(trackInfo.getAlbumId(), orderNum);
		//4.删除声音统计记录
		LambdaQueryWrapper<TrackStat> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(TrackStat::getTrackId, id);
		trackStatMapper.delete(queryWrapper);
		//5.更新专辑包含声音数量减一
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()-1);
		albumInfoMapper.updateById(albumInfo);
		//6.删除云点播平台声音文件
		vodService.deleteTrackMedia(trackInfo.getMediaFileId());
	}

}
